package com.ruyuan.starter.async.autoconfigure;

import com.ruyuan.starter.async.BossEventBus;
import com.ruyuan.starter.async.WorkEventBusManager;
import com.ruyuan.starter.async.anno.Channel;
import com.ruyuan.starter.async.listener.EventListener;
import com.ruyuan.starter.async.thread.ExecutorService;
import com.ruyuan.starter.async.util.CglibUtils;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.Map;

/**
 * @author zhonghuashishan
 */
/*
配置例子
ruyuan:
  async:
    boss:
      ringbufferSize: 65536
      eventHandlerNum: 8
    workers:
      - channel: channel-a
        ringbufferSize: 65536
        eventHandlerNum: 8
      - channel: channel-b
        ringbufferSize: 65536
        eventHandlerNum: 8
  executors:
    - threadPool: channel-a
      threadCount: 8
    - threadPool: channel-b
      threadCount: 8
 */
@Configuration
@EnableConfigurationProperties({BossConfig.class, WorkerConfig.class, ExecutorConfig.class})
public class AsyncAutoConfigure implements ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware {

    private final BossConfig bossConfig;

    private final WorkerConfig workerConfig;

    private final ExecutorConfig executorConfig;

    private ApplicationContext applicationContext;

    public AsyncAutoConfigure(BossConfig bossConfig, WorkerConfig workerConfig, ExecutorConfig executorConfig) {
        this.bossConfig = bossConfig;
        this.workerConfig = workerConfig;
        this.executorConfig = executorConfig;
    }

    @Bean
    @Conditional(EventBusCondition.class)
    @ConditionalOnMissingBean
    public BossEventBus bossEventBus() {
        return new BossEventBus(bossConfig, workerConfig);
    }

    @Bean
    @Conditional(ExecutorCondition.class)
    @ConditionalOnMissingBean
    public ExecutorService executorService() {
        return new ExecutorService(executorConfig);
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        Map<String, EventListener> eventListenerMap = applicationContext.getBeansOfType(EventListener.class);
        WorkEventBusManager workEventBusManager = WorkEventBusManager.getSingleton();
        for (EventListener eventListener : eventListenerMap.values()) {
            // 这里需要过滤一下代理类，比如用了Sentinel啥的，可能就会对bean做增强，
            // 然后getClass获取到的是一个代理类，代理类上是拿不到Channel注解的
            Class<?> realClazz = CglibUtils.filterCglibProxyClass(eventListener.getClass());
            Channel channel = realClazz.getAnnotation(Channel.class);
            if (channel != null && !channel.value().isEmpty()) {
                workEventBusManager.getWorkEventBus(channel.value()).register(eventListener);
            }
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}